package com.springboot.middleware.middleware_redisson.server.service;

import com.springboot.middleware.middleware_redisson.model.entity.BookRob;
import com.springboot.middleware.middleware_redisson.model.entity.BookStock;
import com.springboot.middleware.middleware_redisson.model.mapper.BookRobMapper;
import com.springboot.middleware.middleware_redisson.model.mapper.BookStockMapper;
import com.springboot.middleware.middleware_redisson.server.dto.BookRobDto;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class BookRobServiceRedissonImpl implements BookRobService {
    private static final Logger log = LoggerFactory.getLogger(BookRobServiceRedissonImpl.class);

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private BookStockMapper bookStockMapper;
    @Autowired
    private BookRobMapper bookRobMapper;

    /**
     * 处理书籍抢购逻辑 - 加分布式锁
     *
     * @param dto (用户id, 书籍编号)
     * @throws Exception 书籍库存不足 / 获取分布式锁失败
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rob(BookRobDto dto) throws Exception {
        final String lockName = "redissonTryLock-" + dto.getBookNo() + "-" + dto.getUserId();
        RLock rLock = redissonClient.getLock(lockName);
        try {
            //尝试获取分布式锁,如果返回true, 即代表成果获取到了分布式锁
            boolean result = rLock.tryLock(100, 10, TimeUnit.SECONDS);
            if(result) {
                BookStock bookStock = bookStockMapper.selectByBookNo(dto.getBookNo());
                int total = bookRobMapper.countByUserIdBookNo(dto.getUserId(), dto.getBookNo());
                if (bookStock != null && bookStock.getStock() > 0 && total <= 0) {
                    int res = bookStockMapper.updateStockWithLock(dto.getBookNo());
                    //库存更新成功后, 需要添加抢购记录
                    if (res > 0) {
                        BookRob entry = new BookRob();
                        entry.setBookNo(dto.getBookNo());
                        entry.setUserId(dto.getUserId());
                        entry.setRobTime(new Date());
                        bookRobMapper.insertSelective(entry);
                        log.info("---处理书籍抢购逻辑-加Redisson分布式锁---, 当前线程成功抢到书籍:{}",dto);
                    }
                } else {
                    throw new Exception("该书库存不足");
                }
            } else {
                throw new Exception("--获取Redisson分布式锁失败--");
            }
        } catch (Exception e) {
            log.error("发生籍库存不足 / 获取分布式锁失败以外的异常");
            throw e;
        } finally {
            if (rLock != null) {
                rLock.unlock();
                //在某些严格的业务场景下, 也可以调用强制释放分布式锁的方法
                //rLock.forceUnlock();
            }
        }
    }
}
